home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / f_tv.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  19.5 KB  |  733 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <stdio.h>
  19.  
  20. #include <windows.h>
  21. #include <commctrl.h>
  22. #include <math.h>
  23.  
  24. #include "ScriptInterpreter.h"
  25. #include "ScriptValue.h"
  26. #include "ScriptError.h"
  27.  
  28. #include "resource.h"
  29. #include "filter.h"
  30.  
  31. extern HINSTANCE g_hInst;
  32.  
  33. ///////////////////////////////////
  34.  
  35. #define YIQMODE_Y        (0)
  36. #define YIQMODE_I        (1)
  37. #define YIQMODE_Q        (2)
  38. #define    YIQMODE_IQAVERAGE3 (3)
  39. #define    YIQMODE_IQAVERAGE5 (4)
  40. #define    YIQMODE_IQAV5TMP (5)
  41. #define    YIQMODE_CHROMAUP    (6)
  42. #define YIQMODE_CHROMADOWN    (7)
  43.  
  44. typedef signed long IQPixel;
  45. typedef unsigned char YPixel;
  46.  
  47. typedef struct YIQFilterData {
  48.     int            mode;
  49.     IQPixel        *rows;
  50.     unsigned char *tsramp;
  51.     YPixel        *lummap;
  52.     IQPixel        *iqmap;
  53. } YIQFilterData;
  54.  
  55. static void iq_average_row3(Pixel *_src, IQPixel *_dst, int _count) {
  56.     Pixel *src = _src;
  57.     IQPixel *dst = _dst;
  58.     int count = 1-_count;
  59.  
  60.     Pixel c;
  61.     long r, g, b;
  62.     long    i1, q1,
  63.             i2=0, q2=0,
  64.             i3=0, q3=0;
  65.  
  66.     // dst[0]: [0] [0] [1]
  67.     // dst[2]: [0] [1] [2]
  68.  
  69.     c = *src++;
  70.     r = (c>>16) & 255;
  71.     g = (c>> 8) & 255;
  72.     b = c & 255;
  73.  
  74.     i2 = i1 = 54 * r - 133 * g + 79 * b; // I
  75.     q2 = q1 = 154 * r - 72 * g - 82 * b; // Q
  76.  
  77.     do {
  78.         c = *src++;
  79.         r = (c>>16) & 255;
  80.         g = (c>> 8) & 255;
  81.         b = c & 255;
  82.  
  83.         i3 = i2; q3 = q2;
  84.         i2 = i1; q2 = q1;
  85.         i1 = 54 * r - 133 * g + 79 * b; // I
  86.         q1 = 154 * r - 72 * g - 82 * b; // Q
  87.  
  88.         dst[0] = i1 + i2*2 + i3;
  89.         dst[1] = q1 + q2*2 + q3;
  90.  
  91.         dst+=2;
  92.  
  93.     } while(++count);
  94.  
  95.     dst[0] = i2 + i1*3;
  96.     dst[1] = q2 + q1*3;
  97. }
  98.  
  99. static void iq_average_row5(Pixel *_src, IQPixel *_dst, int _count) {
  100.     Pixel *src = _src;
  101.     IQPixel *dst = _dst;
  102.     int count = 2-_count;
  103.  
  104.     Pixel c;
  105.     long r, g, b;
  106.     long    i1, q1,
  107.             i2=0, q2=0,
  108.             i3=0, q3=0,
  109.             i4=0, q4=0,
  110.             i5=0, q5=0;
  111.  
  112.     // dst[0]: [0] [0] [0] [1] [2]
  113.     // dst[2]: [0] [0] [1] [2] [3]
  114.     // dst[4]: [0] [1] [2] [3] [4]
  115.  
  116.     c = *src++;
  117.     r = (c>>16) & 255;
  118.     g = (c>> 8) & 255;
  119.     b = c & 255;
  120.  
  121.     i4 = i3 = i2 = 54 * r - 133 * g + 79 * b; // I
  122.     q4 = q3 = q2 = 154 * r - 72 * g - 82 * b; // Q
  123.  
  124.     c = *src++;
  125.     r = (c>>16) & 255;
  126.     g = (c>> 8) & 255;
  127.     b = c & 255;
  128.  
  129.     i1 = 54 * r - 133 * g + 79 * b; // I
  130.     q1 = 154 * r - 72 * g - 82 * b; // Q
  131.  
  132.     do {
  133.         c = *src++;
  134.         r = (c>>16) & 255;
  135.         g = (c>> 8) & 255;
  136.         b = c & 255;
  137.  
  138.         i5 = i4; q5 = q4;
  139.         i4 = i3; q4 = q3;
  140.         i3 = i2; q3 = q2;
  141.         i2 = i1; q2 = q1;
  142.         i1 = 54 * r - 133 * g + 79 * b; // I
  143.         q1 = 154 * r - 72 * g - 82 * b; // Q
  144.  
  145.         dst[0] = i1 + i2*2 + i3*2 + i4*2 + i5;
  146.         dst[1] = q1 + q2*2 + q3*2 + q4*2 + q5;
  147.  
  148.         dst+=2;
  149.  
  150.     } while(++count);
  151.  
  152.     // dst[n-6]: [5] [4] [3] [2] [1]
  153.     // dst[n-4]: [4] [3] [2] [1] [1]
  154.     // dst[n-2]: [3] [2] [1] [1] [1]
  155.  
  156.     dst[0] = i1*3 + i2*2 + i3*2 + i4;
  157.     dst[1] = q1*3 + q2*2 + q3*2 + q4;
  158.  
  159.     dst[2] = i1*5 + i2*2 + i3;
  160.     dst[3] = q1*5 + q2*2 + q3;
  161. }
  162.  
  163. // The IQ system sucks for what we do, so we're going to follow
  164. // the lead of modern TVs and use (Y, R-Y, B-Y) instead of (Y, I, Q).
  165. //
  166. //    Forward matrix:
  167. //
  168. //    Y    = 0.30R + 0.59G + 0.11B
  169. //    R-Y    = 0.70R - 0.59G - 0.11B (179, -151, -28)
  170. //    B-Y    =-0.30R - 0.59G + 0.89B (-77, -151, 228)
  171. //
  172. //    Inverse matrix:
  173. //
  174. //    R = Y + (R-Y)
  175. //    G = Y - 0.50847(R-Y) - 0.18644(B-Y)
  176. //    B = Y + (B-Y)
  177.  
  178. static void rb_average_row3(Pixel *_src, IQPixel *_dst, int _count) {
  179.     Pixel *src = _src;
  180.     IQPixel *dst = _dst;
  181.     int count = 2-_count;
  182.  
  183.     // dst[0]: [0] [0] [1]
  184.     // dst[2]: [0] [1] [2]
  185.  
  186.     *dst    = ((((src[0]&0x00ff00ff)*3 + (src[1]&0x00ff00ff))>>2)&0x00ff00ff)
  187.             | ((((src[0]&0x0000ff00)*3 + (src[1]&0x0000ff00))>>2)&0x0000ff00);
  188.     src++;
  189.     dst++;
  190.  
  191.     do {
  192.         *dst    = ((((src[-1]&0x00ff00ff) + (src[0]&0x00ff00ff)*2 + (src[1]&0x00ff00ff))>>2)&0x00ff00ff)
  193.                 | ((((src[-1]&0x0000ff00) + (src[0]&0x0000ff00)*2 + (src[1]&0x0000ff00))>>2)&0x0000ff00);
  194.         ++src;
  195.  
  196.         dst++;
  197.  
  198.     } while(++count);
  199.  
  200.     *dst    = ((((src[-1]&0x00ff00ff)*3 + (src[0]&0x00ff00ff)*3)>>2)&0x00ff00ff)
  201.             | ((((src[-1]&0x0000ff00)*3 + (src[0]&0x0000ff00)*3)>>2)&0x0000ff00);
  202. }
  203.  
  204. static void rb_average_row5(Pixel *_src, IQPixel *_dst, int _count) {
  205.     Pixel *src = _src;
  206.     IQPixel *dst = _dst;
  207.     int count = 4-_count;
  208.  
  209.     // dst[0]: [0] [0] [1]
  210.     // dst[2]: [0] [1] [2]
  211.  
  212.     *dst    = ((((src[0]&0x00ff00ff)*5 + (src[1]&0x00ff00ff)*2 + (src[2]&0x00ff00ff))>>3)&0x00ff00ff)
  213.             | ((((src[0]&0x0000ff00)*5 + (src[1]&0x0000ff00)*2 + (src[2]&0x0000ff00))>>3)&0x0000ff00);
  214.     src++;
  215.     dst++;
  216.  
  217.     *dst    = ((((src[-1]&0x00ff00ff)*3 + (src[0]&0x00ff00ff)*2 + (src[1]&0x00ff00ff)*2 + (src[2]&0x00ff00ff))>>3)&0x00ff00ff)
  218.             | ((((src[-1]&0x0000ff00)*3 + (src[0]&0x0000ff00)*2 + (src[1]&0x0000ff00)*2 + (src[2]&0x0000ff00))>>3)&0x0000ff00);
  219.     src++;
  220.     dst++;
  221.  
  222.     do {
  223.         *dst    = ((((src[-2]&0x00ff00ff) + (src[-1]&0x00ff00ff)*2 + (src[0]&0x00ff00ff)*2 + (src[1]&0x00ff00ff)*2 + (src[2]&0x00ff00ff))>>3)&0x00ff00ff)
  224.                 | ((((src[-2]&0x0000ff00) + (src[-1]&0x0000ff00)*2 + (src[0]&0x0000ff00)*2 + (src[1]&0x0000ff00)*2 + (src[2]&0x0000ff00))>>3)&0x0000ff00);
  225.         ++src;
  226.  
  227.         dst++;
  228.  
  229.     } while(++count);
  230.  
  231.     *dst    = ((((src[-2]&0x00ff00ff) + (src[-1]&0x00ff00ff)*2 + (src[0]&0x00ff00ff)*2 + (src[1]&0x00ff00ff)*3)>>3)&0x00ff00ff)
  232.             | ((((src[-2]&0x0000ff00) + (src[-1]&0x0000ff00)*2 + (src[0]&0x0000ff00)*2 + (src[1]&0x0000ff00)*3)>>3)&0x0000ff00);
  233.     ++src;
  234.     dst++;
  235.  
  236.     *dst    = ((((src[-2]&0x00ff00ff) + (src[-1]&0x00ff00ff)*2 + (src[0]&0x00ff00ff)*5)>>3)&0x00ff00ff)
  237.             | ((((src[-2]&0x0000ff00) + (src[-1]&0x0000ff00)*2 + (src[0]&0x0000ff00)*5)>>3)&0x0000ff00);
  238. }
  239.  
  240. //#define USE_YIQ_SPACE
  241.  
  242. extern "C" void asm_tv_average5row(Pixel *src, IQPixel *dst, int count);
  243. extern "C" asm_tv_average5col(Pixel *, IQPixel *, IQPixel *, IQPixel *, IQPixel *, IQPixel *, long);
  244.  
  245. static void ChromaShift(Pixel32 *dst0, Pixel32 *src0, PixOffset dstpitch, PixOffset srcpitch, PixDim w, PixDim h) {
  246.     PixDim wt;
  247.  
  248.     do {
  249.         Pixel32 *src = src0;
  250.         Pixel32 *dst = dst0;
  251.  
  252.         wt = w;
  253.         do {
  254.             Pixel32 cs = *src;
  255.             Pixel32 cd = *dst;
  256.             int ydiff;
  257.             int r, g, b;
  258.  
  259.             r = (cs>>16)&255;
  260.             g = (cs>>8)&255;
  261.             b = cs&255;
  262.  
  263.             ydiff = (54*((int)((cd>>16)&255)-r)+183*((int)((cd&0xff00)>>8)-g)+19*((int)(cd&255) - b) + 128) >> 8;
  264.  
  265.             r += ydiff;
  266.             g += ydiff;
  267.             b += ydiff;
  268.  
  269.             if (r<0) r=0; else if (r>255) r=255;
  270.             if (g<0) g=0; else if (g>255) g=255;
  271.             if (b<0) b=0; else if (b>255) b=255;
  272.  
  273.             *dst = (r<<16) + (g<<8) + b;
  274.  
  275.             ++src, ++dst;
  276.         } while(--wt);
  277.  
  278.         src0 = (Pixel32 *)((char *)src0 + srcpitch);
  279.         dst0 = (Pixel32 *)((char *)dst0 + dstpitch);
  280.     } while(--h);
  281. }
  282.  
  283. static int yiq_run(const FilterActivation *fa, const FilterFunctions *ff) {
  284.     YIQFilterData *mfd = (YIQFilterData *)fa->filter_data;
  285.     Pixel *dst = (Pixel *)fa->dst.data;
  286.     long w, h;
  287.     Pixel c;
  288.  
  289.     if (mfd->mode == YIQMODE_IQAVERAGE3) {
  290.         IQPixel *row_p = mfd->rows,
  291.                 *row_c = mfd->rows + 1*fa->dst.w,
  292.                 *row_n = mfd->rows + 2*fa->dst.w,
  293.                 *row_t;
  294.  
  295.         IQPixel *r1, *r2, *r3;
  296.  
  297.         rb_average_row3(dst, row_p, fa->dst.w);
  298.  
  299.         memcpy(row_c, row_p, sizeof(IQPixel) * 1 * fa->dst.w);
  300.  
  301.         h = fa->dst.h;
  302.         do {
  303.             if (h>1)
  304.                 rb_average_row3((Pixel *)((char *)dst + fa->dst.pitch), row_n, fa->dst.w);
  305.             else
  306.                 row_n = row_c;
  307.  
  308.             r1 = row_p;
  309.             r2 = row_c;
  310.             r3 = row_n;
  311.  
  312.             w = fa->dst.w;
  313.             do {
  314.                 Pixel c, d;
  315.                 long y, r, g, b;
  316.     
  317.                 c = *dst;
  318.                 d    = ((((r1[0] & 0x00ff00ff) + 2*(r2[0] & 0x00ff00ff) + (r3[0] & 0x00ff00ff))>>2) & 0x00ff00ff)
  319.                     | ((((r1[0] & 0x0000ff00) + 2*(r2[0] & 0x0000ff00) + (r3[0] & 0x0000ff00))>>2) & 0x0000ff00);
  320.  
  321.                 y    = ((54*((c>>16)&255) + 183*((c>>8)&255) + 19*(c&255))>>8)
  322.                     - ((54*((d>>16)&255) + 183*((d>>8)&255) + 19*(d&255))>>8);
  323.  
  324.                 r = ((d>>16)&255) + y;
  325.                 g = ((d>> 8)&255) + y;
  326.                 b = ((d    )&255) + y;
  327.  
  328.                 r1++;
  329.                 r2++;
  330.                 r3++;
  331.  
  332.                 // [r]   [ 256  160  243][y]
  333.                 // [g] = [ 256 -164  -71][i]
  334.                 // [b]   [ 256  443 -283][q]
  335.  
  336.                 if (r<0) r=0; else if (r>255) r=255;
  337.                 if (g<0) g=0; else if (g>255) g=255;
  338.                 if (b<0) b=0; else if (b>255) b=255;
  339.  
  340.                 *dst++ = (r<<16) + (g<<8) + b;
  341.             } while(--w);
  342.  
  343.             row_t = row_p; row_p = row_c; row_c = row_n; row_n = row_t;
  344.  
  345.             dst = (Pixel *)((char *)dst + fa->dst.modulo);
  346.         } while(--h);
  347.     } else if (mfd->mode == YIQMODE_IQAVERAGE5) {
  348.         IQPixel *row_f = mfd->rows,
  349.                 *row_p = mfd->rows + 1*fa->dst.w,
  350.                 *row_c = mfd->rows + 2*fa->dst.w,
  351.                 *row_n = mfd->rows + 3*fa->dst.w,
  352.                 *row_l = mfd->rows + 4*fa->dst.w,
  353.                 *row_t;
  354.  
  355.         IQPixel *r1, *r2, *r3, *r4, *r5;
  356.  
  357.         rb_average_row5(dst, row_f, fa->dst.w);
  358.  
  359.         memcpy(row_p, row_f, sizeof(IQPixel) * 2 * fa->dst.w);
  360.         memcpy(row_c, row_f, sizeof(IQPixel) * 2 * fa->dst.w);
  361.  
  362.         asm_tv_average5row/*rb_average_row5*/((Pixel *)((char *)dst + fa->dst.pitch), row_n, fa->dst.w);
  363.  
  364.         h = fa->dst.h;
  365.         do {
  366.             if (h>2)
  367.                 asm_tv_average5row/*/rb_average_row5*/((Pixel *)((char *)dst + fa->dst.pitch*2), row_l, fa->dst.w);
  368.             else
  369.                 row_l = row_n;
  370.  
  371.             r1 = row_f;
  372.             r2 = row_p;
  373.             r3 = row_c;
  374.             r4 = row_n;
  375.             r5 = row_l;
  376.  
  377. #if 1
  378.  
  379.             asm_tv_average5col(dst, r1, r2, r3, r4, r5, fa->dst.w);
  380.             dst += fa->dst.w;
  381. #else
  382.             w = fa->dst.w;
  383.             do {
  384.                 Pixel c, d;
  385.                 long y, r, g, b;
  386.     
  387.                 c = *dst;
  388.                 d    = ((((r1[0] & 0x00ff00ff) + 2*(r2[0] & 0x00ff00ff) + 2*(r3[0] & 0x00ff00ff) + 2*(r4[0] & 0x00ff00ff) + (r5[0] & 0x00ff00ff))>>3) & 0x00ff00ff)
  389.                     | ((((r1[0] & 0x0000ff00) + 2*(r2[0] & 0x0000ff00) + 2*(r3[0] & 0x0000ff00) + 2*(r4[0] & 0x0000ff00) + (r5[0] & 0x0000ff00))>>3) & 0x0000ff00);
  390.  
  391. #if 0
  392.                 y    = ((54*((c>>16)&255) + 183*((c>>8)&255) + 19*(c&255))>>8)
  393.                     - ((54*((d>>16)&255) + 183*((d>>8)&255) + 19*(d&255))>>8);
  394. #else
  395.                 y    =( 54*((long)((c>>16)&255) - (long)((d>>16)&255))
  396.                     + 183*((long)((c>> 8)&255) - (long)((d>> 8)&255))
  397.                     +  19*((long)((c    )&255) - (long)((d    )&255)))>>8;
  398. #endif
  399.                 r = ((d>>16)&255) + y;
  400.                 g = ((d>> 8)&255) + y;
  401.                 b = ((d    )&255) + y;
  402.  
  403.                 r1++;
  404.                 r2++;
  405.                 r3++;
  406.                 r4++;
  407.                 r5++;
  408.  
  409.                 // [r]   [ 256  160  243][y]
  410.                 // [g] = [ 256 -164  -71][i]
  411.                 // [b]   [ 256  443 -283][q]
  412.  
  413.                 if (r<0) r=0; else if (r>255) r=255;
  414.                 if (g<0) g=0; else if (g>255) g=255;
  415.                 if (b<0) b=0; else if (b>255) b=255;
  416.  
  417.                 *dst++ = (r<<16) + (g<<8) + b;
  418.             } while(--w);
  419. #endif
  420.  
  421.             row_t = row_f;
  422.             row_f = row_p;
  423.             row_p = row_c;
  424.             row_c = row_n;
  425.             row_n = row_l;
  426.             row_l = row_t;
  427.  
  428.             dst = (Pixel *)((char *)dst + fa->dst.modulo);
  429.         } while(--h);
  430.     } else if (mfd->mode == YIQMODE_IQAV5TMP) {
  431.         IQPixel *row_f = mfd->rows,
  432.                 *row_p = mfd->rows + 2*fa->dst.w,
  433.                 *row_c = mfd->rows + 4*fa->dst.w,
  434.                 *row_n = mfd->rows + 6*fa->dst.w,
  435.                 *row_l = mfd->rows + 8*fa->dst.w,
  436.                 *row_t;
  437.  
  438.         IQPixel *r1, *r2, *r3, *r4, *r5;
  439.         YPixel *ly = mfd->lummap;
  440.         IQPixel *liq = mfd->iqmap;
  441.  
  442.         iq_average_row5(dst, row_f, fa->dst.w);
  443.         memcpy(row_p, row_f, sizeof(IQPixel) * 2 * fa->dst.w);
  444.         memcpy(row_c, row_f, sizeof(IQPixel) * 2 * fa->dst.w);
  445.  
  446.         iq_average_row5((Pixel *)((char *)dst + fa->dst.pitch), row_n, fa->dst.w);
  447.  
  448.         h = fa->dst.h;
  449.         do {
  450.             if (h>2)
  451.                 iq_average_row5((Pixel *)((char *)dst + fa->dst.pitch*2), row_l, fa->dst.w);
  452.             else
  453.                 row_l = row_n;
  454.  
  455.             r1 = row_f;
  456.             r2 = row_p;
  457.             r3 = row_c;
  458.             r4 = row_n;
  459.             r5 = row_l;
  460.  
  461.             w = fa->dst.w;
  462.             do {
  463.                 Pixel c;
  464.                 long y, i, q, r, g, b;
  465.                 long m;
  466.     
  467.                 c = *dst;
  468.  
  469.                 y = 4915 * ((c>>16) & 255) + 9667 * ((c>>8) & 255) + 1802 * (c & 255);
  470.                 i = ((long)r1[0] + 2*(long)r2[0] + 2*(long)r3[0] + 2*(long)r4[0] + (long)r5[0] + 128)>>8;
  471.                 q = ((long)r1[1] + 2*(long)r2[1] + 2*(long)r3[1] + 2*(long)r4[1] + (long)r5[1] + 128)>>8;
  472.  
  473.                 r1 += 2;
  474.                 r2 += 2;
  475.                 r3 += 2;
  476.                 r4 += 2;
  477.                 r5 += 2;
  478.  
  479.                 // [r]   [ 256  160  243][y]
  480.                 // [g] = [ 256 -164  -71][i]
  481.                 // [b]   [ 256  443 -283][q]
  482.  
  483.                 m = mfd->tsramp[255 + ((y+8192)>>14) - *ly];
  484.                 *ly++ = ((y+8192)>>14);
  485.  
  486.                 liq[0] = i = (liq[0]*m + i*(256-m))>>8;
  487.                 liq[1] = q = (liq[1]*m + q*(256-m))>>8;
  488.  
  489.                 liq += 2;
  490.  
  491.                 r = (y + 160*i + 243*q + 8192) >> 14;
  492.                 g = (y - 164*i -  71*q + 8192) >> 14;
  493.                 b = (y + 443*i - 283*q + 8192) >> 14;
  494.  
  495.                 if (r<0) r=0; else if (r>255) r=255;
  496.                 if (g<0) g=0; else if (g>255) g=255;
  497.                 if (b<0) b=0; else if (b>255) b=255;
  498.  
  499.                 *dst++ = (r<<16) + (g<<8) + b;
  500.             } while(--w);
  501.  
  502.             row_t = row_f;
  503.             row_f = row_p;
  504.             row_p = row_c;
  505.             row_c = row_n;
  506.             row_n = row_l;
  507.             row_l = row_t;
  508.  
  509.             dst = (Pixel *)((char *)dst + fa->dst.modulo);
  510.         } while(--h);
  511.     } else if (mfd->mode == YIQMODE_CHROMAUP) {
  512.         ChromaShift(fa->src.Address32(0,0), fa->src.Address32(0,1), -fa->src.pitch, -fa->src.pitch, fa->src.w, fa->src.h-1);
  513.     } else if (mfd->mode == YIQMODE_CHROMADOWN) {
  514.         ChromaShift(fa->src.Address32i(0,0), fa->src.Address32i(0,1), fa->src.pitch, fa->src.pitch, fa->src.w, fa->src.h-1);
  515.     } else {
  516.         int cr, cg, cb, bias;
  517.         int v;
  518.  
  519.         switch(mfd->mode) {
  520.         case YIQMODE_Y:
  521.             cr = (int)(+0.30 * 256 + 0.5);
  522.             cg = (int)(+0.59 * 256 + 0.5);
  523.             cb = (int)(+0.11 * 256 + 0.5);
  524.             bias = 0;
  525.             break;
  526.  
  527.         case YIQMODE_I:
  528.             cr = (int)(+0.21 * 256 + 0.5);
  529.             cg = (int)(-0.52 * 256 + 0.5);
  530.             cb = (int)(+0.31 * 256 + 0.5);
  531.             bias = 128 * 256;
  532.             break;
  533.  
  534.         case YIQMODE_Q:
  535.             cr = (int)(+0.60 * 256 + 0.5);
  536.             cg = (int)(-0.28 * 256 + 0.5);
  537.             cb = (int)(-0.32 * 256 + 0.5);
  538.             bias = 128 * 256;
  539.             break;
  540.  
  541.         }
  542.  
  543.         h = fa->dst.h;
  544.         do {
  545.             w = fa->dst.w;
  546.             do {
  547.                 c = *dst;
  548.                 v = (cr * ((c>>16)&255) + cg * ((c>>8)&255) + cb * (c&255) + bias)>>8;
  549.  
  550.                 if (v<0) v=0; else if (v>255) v=255;
  551.  
  552.                 *dst++ = v + (v<<8) + (v<<16);
  553.             } while(--w);
  554.  
  555.             dst = (Pixel *)((char *)dst + fa->dst.modulo);
  556.         } while(--h);
  557.     }
  558.  
  559.     return 0;
  560. }
  561.  
  562. static long yiq_param(FilterActivation *fa, const FilterFunctions *ff) {
  563.     fa->dst.offset = fa->src.offset;
  564.     return 0;
  565. }
  566.  
  567. /////////////////////////////////////////////////////////////
  568.  
  569. static BOOL APIENTRY YIQConfigDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  570.     switch (message)
  571.     {
  572.         case WM_INITDIALOG:
  573.             SetWindowLong(hDlg, DWL_USER, lParam);
  574.             CheckDlgButton(hDlg, IDC_MODE_Y, ((YIQFilterData *)lParam)->mode == YIQMODE_Y);
  575.             CheckDlgButton(hDlg, IDC_MODE_I, ((YIQFilterData *)lParam)->mode == YIQMODE_I);
  576.             CheckDlgButton(hDlg, IDC_MODE_Q, ((YIQFilterData *)lParam)->mode == YIQMODE_Q);
  577.             CheckDlgButton(hDlg, IDC_MODE_IQAVERAGE3, ((YIQFilterData *)lParam)->mode == YIQMODE_IQAVERAGE3);
  578.             CheckDlgButton(hDlg, IDC_MODE_IQAVERAGE5, ((YIQFilterData *)lParam)->mode == YIQMODE_IQAVERAGE5);
  579.             CheckDlgButton(hDlg, IDC_MODE_IQAV5TMP, ((YIQFilterData *)lParam)->mode == YIQMODE_IQAV5TMP);
  580.             CheckDlgButton(hDlg, IDC_MODE_CHROMAUP, ((YIQFilterData *)lParam)->mode == YIQMODE_CHROMAUP);
  581.             CheckDlgButton(hDlg, IDC_MODE_CHROMADOWN, ((YIQFilterData *)lParam)->mode == YIQMODE_CHROMADOWN);
  582.             return (TRUE);
  583.  
  584.         case WM_COMMAND:                 
  585.             switch(LOWORD(wParam)) {
  586.  
  587.             case IDOK:
  588.                 {
  589.                     YIQFilterData *mfd = (YIQFilterData *)GetWindowLong(hDlg, DWL_USER);
  590.  
  591.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_Y)) mfd->mode = YIQMODE_Y;
  592.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_I)) mfd->mode = YIQMODE_I;
  593.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_Q)) mfd->mode = YIQMODE_Q;
  594.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_IQAVERAGE3)) mfd->mode = YIQMODE_IQAVERAGE3;
  595.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_IQAVERAGE5)) mfd->mode = YIQMODE_IQAVERAGE5;
  596.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_IQAV5TMP)) mfd->mode = YIQMODE_IQAV5TMP;
  597.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_CHROMAUP)) mfd->mode = YIQMODE_CHROMAUP;
  598.                     if (IsDlgButtonChecked(hDlg, IDC_MODE_CHROMADOWN)) mfd->mode = YIQMODE_CHROMADOWN;
  599.                 }
  600.                 EndDialog(hDlg, 0);
  601.                 return TRUE;
  602.  
  603.             case IDCANCEL:
  604.                 EndDialog(hDlg, 1);
  605.                 return TRUE;
  606.  
  607.             }
  608.             break;
  609.     }
  610.     return FALSE;
  611. }
  612.  
  613. static int yiq_config(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd) {
  614.     return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_YIQ_CONFIG), hWnd, YIQConfigDlgProc, (LPARAM)fa->filter_data);
  615. }
  616.  
  617. /////////////////////////////////////////////////////////////
  618.  
  619. static void yiq_string(const FilterActivation *fa, const FilterFunctions *ff, char *buf) {
  620.     YIQFilterData *mfd = (YIQFilterData *)fa->filter_data;
  621.  
  622.     wsprintf(buf, " (%s)", mfd ? (
  623.                             mfd->mode==YIQMODE_Y ? "Y channel" :
  624.                             mfd->mode==YIQMODE_I ? "I channel" :
  625.                             mfd->mode==YIQMODE_Q ? "Q channel" :
  626.                             mfd->mode==YIQMODE_IQAVERAGE3 ? "I/Q 3x3 average" :
  627.                             mfd->mode==YIQMODE_IQAVERAGE5 ? "I/Q 5x5 average" :
  628.                             mfd->mode==YIQMODE_IQAV5TMP ? "I/Q 5x5 + t/s" :
  629.                             mfd->mode==YIQMODE_CHROMAUP ? "chroma up" :
  630.                             "chroma down"
  631.                         ) : "unconfigured");
  632. }
  633.  
  634. static int yiq_start(FilterActivation *fa, const FilterFunctions *ff) {
  635.     YIQFilterData *mfd = (YIQFilterData *)fa->filter_data;
  636.  
  637.     if (mfd->mode == YIQMODE_IQAVERAGE3) {
  638.         if (!(mfd->rows = new IQPixel[fa->dst.w * 3]))
  639.             return 1;
  640.     } else if (mfd->mode == YIQMODE_IQAVERAGE5) {
  641.         if (!(mfd->rows = new IQPixel[fa->dst.w * 5]))
  642.             return 1;
  643.     } else if (mfd->mode == YIQMODE_IQAV5TMP) {
  644.         if (!(mfd->rows = new IQPixel[fa->dst.w * 10]))
  645.             return 1;
  646.  
  647.         if (!(mfd->lummap = new YPixel[fa->dst.w * fa->dst.h]))
  648.             return 1;
  649.  
  650.         memset(mfd->lummap, 0x80, sizeof(YPixel)*fa->dst.w*fa->dst.h);
  651.  
  652.         if (!(mfd->iqmap = new IQPixel[fa->dst.w * fa->dst.h * 2]))
  653.             return 1;
  654.  
  655.         memset(mfd->iqmap, 0, sizeof(IQPixel)*fa->dst.w*fa->dst.h*2);
  656.  
  657.         if (!(mfd->tsramp = new unsigned char [511]))
  658.             return 1;
  659.  
  660.         // initialize tsramp
  661.  
  662.         int i;
  663.  
  664.         for(i=0; i<16; i++) {
  665.             mfd->tsramp[255 + i] = 192;
  666.             mfd->tsramp[255 - i] = 192;
  667.         }
  668.         for(; i<112; i++) {
  669.             mfd->tsramp[255 + i] = (112-i)<<1;
  670.             mfd->tsramp[255 - i] = (112-1)<<1;
  671.         }
  672.         for(; i<256; i++) {
  673.             mfd->tsramp[255 + i] = 0;
  674.             mfd->tsramp[255 - i] = 0;
  675.         }
  676.     }
  677.  
  678.     return 0;
  679. }
  680.  
  681. static int yiq_end(FilterActivation *fa, const FilterFunctions *ff) {
  682.     YIQFilterData *mfd = (YIQFilterData *)fa->filter_data;
  683.  
  684.     delete[] mfd->rows;        mfd->rows = NULL;
  685.     delete[] mfd->lummap;    mfd->lummap = NULL;
  686.     delete[] mfd->iqmap;    mfd->iqmap = NULL;
  687.     delete[] mfd->tsramp;    mfd->tsramp = NULL;
  688.  
  689.     return 0;
  690. }
  691.  
  692. static void yiq_script_config(IScriptInterpreter *isi, void *lpVoid, CScriptValue *argv, int argc) {
  693.     FilterActivation *fa = (FilterActivation *)lpVoid;
  694.     YIQFilterData *mfd = (YIQFilterData *)fa->filter_data;
  695.  
  696.     mfd->mode = argv[0].asInt();
  697. }
  698.  
  699. static ScriptFunctionDef yiq_func_defs[]={
  700.     { (ScriptFunctionPtr)yiq_script_config, "Config", "0i" },
  701.     { NULL },
  702. };
  703.  
  704. static CScriptObject yiq_obj={
  705.     NULL, yiq_func_defs
  706. };
  707.  
  708. static bool yiq_script_line(FilterActivation *fa, const FilterFunctions *ff, char *buf, int buflen) {
  709.     YIQFilterData *mfd = (YIQFilterData *)fa->filter_data;
  710.  
  711.     _snprintf(buf, buflen, "Config(%d)", mfd->mode);
  712.  
  713.     return true;
  714. }
  715.  
  716. struct FilterDefinition filterDef_tv={
  717.     0,0,NULL,
  718.     "TV",
  719.     "Processes video data in NTSC native YIQ format.",
  720.     NULL,
  721.     NULL,
  722.     sizeof(YIQFilterData),
  723.     NULL,NULL,
  724.     yiq_run,
  725.     yiq_param,
  726.     yiq_config,
  727.     yiq_string,
  728.     yiq_start,
  729.     yiq_end,
  730.     &yiq_obj,
  731.     yiq_script_line
  732. };
  733.